#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
#include <stdbool.h>

// 控制台操作相关定义
HANDLE hOut;
CONSOLE_CURSOR_INFO cci;
COORD coord = {0, 0};

// 游戏常量定义
#define WALL '#'
#define BODY 'O'
#define FOOD '@'
#define INIT_LEN 4
#define MAX_LEVEL 5

// 方向控制枚举
typedef enum {UP, DOWN, LEFT, RIGHT, SPACE} DIR;
// 游戏状态枚举
typedef enum {RUNNING, PAUSE, FAIL, QUIT} GAME_STATUS;

// 全局变量
int sleeptime = 200;    // 刷新间隔
int score = 0;          // 当前得分
int level = 1;          // 当前等级
int add = 10;           // 每个食物得分
GAME_STATUS status;     // 游戏状态
DIR dir;                // 当前方向

// 坐标结构体
typedef struct {
	int x;
	int y;
} Snakenode;

typedef struct {
	Snakenode* nodes;
	int capacity;
	int length;
} Snake;

Snake snake;        // 蛇身体
Snakenode food;     // 食物位置
int highscore;      // 最高分

// 函数声明
void Welcome();
void InitGame();
void CreateMap();
void CreateFood();
void PrintInfo();
void GameOver();
void KeyboardControl();
void SaveScore();
void LoadScore();
void Explation();

// 设置光标位置
void SetPos(int x, int y) {
	coord.X = x;
	coord.Y = y;
	SetConsoleCursorPosition(hOut, coord);
}

// 初始化动态数组
void InitSnake(Snake* s, int capacity) {
	s->nodes = (Snakenode*)malloc(capacity * sizeof(Snakenode));
	s->capacity = capacity;
	s->length = 0;
}

// 添加元素到动态数组头部
void InsertHead(Snake* s, Snakenode node) {
	if (s->length >= s->capacity) {
		s->capacity *= 2;
		s->nodes = (Snakenode*)realloc(s->nodes, s->capacity * sizeof(Snakenode));
	}
	for (int i = s->length; i > 0; i--) {
		s->nodes[i] = s->nodes[i-1];
	}
	s->nodes[0] = node;
	s->length++;
}

// 移除尾部元素
void RemoveTail(Snake* s) {
	if (s->length > 0) {
		s->length--;
	}
}

// 欢迎界面
void Welcome() {
	SetConsoleTextAttribute(hOut, FOREGROUND_GREEN);
	SetPos(35, 10);
	printf("欢迎来到贪吃蛇游戏！");
	SetPos(35, 12);
	printf("1.开始游戏");
	SetPos(35, 13);
	printf("2.游戏说明");
	SetPos(35, 14);
	printf("3.退出游戏");
	
	while (1) 
	{
		char key = _getch();
		if (key == '1') {
			system("cls");
			InitGame();
			return;
		}
		else if (key == '2') {
			system("cls");
			Explation();
			system("cls");
			Welcome();
			return;
		}
		else if (key == '3') {
			exit(0);
		}
	}
}

// 初始化游戏
void InitGame() {
	status = RUNNING;
	dir = RIGHT;
	score = 0;
	level = 1;
	add = 10;
	sleeptime = 200;
	
	// 初始化蛇身
	if (snake.nodes) free(snake.nodes);
	InitSnake(&snake, INIT_LEN);
// 修改循环顺序，从后向前插入，确保蛇头在右侧
	for (int i = INIT_LEN - 1; i >= 0; --i) {
		Snakenode node = {24 - 2 * i, 5};
		InsertHead(&snake, node);
	}
	
	CreateMap();
	LoadScore();
	CreateFood();
	PrintInfo();
}

// 创建地图
void CreateMap() {
	SetConsoleTextAttribute(hOut, FOREGROUND_BLUE);
	// 绘制上下边框
	for (int i = 0; i < 58; i += 2) {
		SetPos(i, 0);
		putchar(WALL);
		SetPos(i, 26);
		putchar(WALL);
	}
	// 绘制左右边框
	for (int i = 1; i < 26; ++i) {
		SetPos(0, i);
		putchar(WALL);
		SetPos(56, i);
		putchar(WALL);
	}
}

// 生成食物
void CreateFood() {
	srand(time(NULL));
	bool inSnake;
	do {
		inSnake = false;
		food.x = rand() % (54 / 2) * 2 + 2;
		food.y = rand() % 24 + 1;
		
		// 检查是否与蛇身重叠
		for (int i = 0; i < snake.length; i++) {
			if (snake.nodes[i].x == food.x && snake.nodes[i].y == food.y) {
				inSnake = true;
				break;
			}
		}
	} while (inSnake || food.x >= 56 || food.y >= 26);
	
	SetConsoleTextAttribute(hOut, FOREGROUND_RED | FOREGROUND_GREEN);
	SetPos(food.x, food.y);
	putchar(FOOD);
}

// 显示游戏信息
void PrintInfo() {
	SetConsoleTextAttribute(hOut, FOREGROUND_GREEN);
	SetPos(60, 4);
	printf("当前得分：%d", score);
	SetPos(60, 6);
	printf("最高分：%d", highscore);
	SetPos(60, 8);
	printf("当前等级：%d", level);
	SetPos(60, 12);
	printf("操作说明：");
	SetPos(60, 14);
	printf("方向键控制移动");
	SetPos(60, 16);
	printf("空格键暂停");
	SetPos(60, 18);
	printf("F1加速 F2减速");
}

// 移动蛇
void MoveSnake() {
	Snakenode head = snake.nodes[0];
	
	// 计算新头部位置
	switch (dir) {
		case UP:    head.y--; break;
		case DOWN:  head.y++; break;
		case LEFT:  head.x -= 2; break;
		case RIGHT: head.x += 2; break;
		default: break;
	}
	
	// 碰撞检测
	if (head.x <= 0 || head.x >= 56 || head.y <= 0 || head.y >= 26) {
		status = FAIL;
		return;
	}
	
	// 自检碰撞
	for (int i = 0; i < snake.length; i++) {
		if (head.x == snake.nodes[i].x && head.y == snake.nodes[i].y) {
			status = FAIL;
			return;
		}
	}
	
	// 吃食物检测
	if (head.x == food.x && head.y == food.y) {
		InsertHead(&snake, head);
		score += add;
		CreateFood();
		if (score / 100 > level && level < MAX_LEVEL) {
			level++;
			sleeptime = (sleeptime > 50) ? sleeptime - 30 : 50;
			add += 5;
		}
		PrintInfo();
	}
	else {
		InsertHead(&snake, head);
		SetConsoleTextAttribute(hOut, FOREGROUND_RED | FOREGROUND_GREEN);
		SetPos(snake.nodes[snake.length-1].x, snake.nodes[snake.length-1].y);
		printf("  ");
		RemoveTail(&snake);
	}
	
	// 绘制新头部
	SetConsoleTextAttribute(hOut, FOREGROUND_GREEN);
	SetPos(head.x, head.y);
	putchar(BODY);
}

// 键盘控制
void KeyboardControl() {
	while (_kbhit()) {
		int ch = _getch();
		if (ch == 0x00 || ch == 0xE0) {
			int ext = _getch();
			switch (ext) {
				// 方向键
				case 72: if (dir != DOWN) dir = UP; break;
				case 80: if (dir != UP) dir = DOWN; break;
				case 75: if (dir != RIGHT) dir = LEFT; break;
				case 77: if (dir != LEFT) dir = RIGHT; break;
				// 功能键
				case 0x3B: // F1
				if (sleeptime > 50) {
					sleeptime = (sleeptime > 50) ? sleeptime - 30 : 50;
					add += 2;
					PrintInfo();
				}
				break;
				case 0x3C: // F2
				if (sleeptime < 350) {
					sleeptime = (sleeptime < 350) ? sleeptime + 30 : 350;
					add = (add > 2) ? add - 2 : 1;
					PrintInfo();
				}
				break;
			}
		}
		else {
			switch (ch) {
				case 'w': case 'W': if (dir != DOWN) dir = UP; break;
				case 's': case 'S': if (dir != UP) dir = DOWN; break;
				case 'a': case 'A': if (dir != RIGHT) dir = LEFT; break;
				case 'd': case 'D': if (dir != LEFT) dir = RIGHT; break;
				case ' ': 
				status = (status == PAUSE) ? RUNNING : PAUSE;
				PrintInfo();
				break;
				case 27: status = QUIT; break; // ESC
			}
		}
	}
}

// 加载最高分
void LoadScore() {
	FILE* fp = fopen("save.txt", "r");
	if (fp) {
		fscanf(fp, "%d", &highscore);
		fclose(fp);
	}
	else {
		highscore = 0;
	}
}

// 保存最高分
void SaveScore() {
	if (score > highscore) {
		FILE* fp = fopen("save.txt", "w");
		fprintf(fp, "%d", score);
		fclose(fp);
		highscore = score;
	}
}

// 游戏结束界面
void GameOver() {
	system("cls");
	
	/* 新增：保存旧的最高分 */
	int old_highscore = highscore;
	SaveScore();  // 这个函数会更新highscore
	
	SetConsoleTextAttribute(hOut, FOREGROUND_RED);
	SetPos(30, 8);
	printf("游戏结束！最终得分：%d", score);
	SetPos(30, 10);
	
	/* 修改判断条件为与旧最高分比较 */
	if (score > old_highscore) {  // 这里用保存前的最高分比较
		printf("创纪录啦！新最高分！");
	} else {
		printf("距离最高分还差：%d", old_highscore - score);
	}
	
	SetConsoleTextAttribute(hOut, FOREGROUND_GREEN);
	SetPos(30, 14);
	printf("1.重新开始");
	SetPos(30, 15);
	printf("2.退出游戏");
	
	while (1) {
		char key = _getch();
		if (key == '1') {
			system("cls");
			InitGame();
			return;
		}
		else if (key == '2') {
			exit(0);
		}
	}
}

// 游戏说明
void Explation() {
	system("cls");
	SetConsoleTextAttribute(hOut, FOREGROUND_GREEN);
	SetPos(15, 5);
	printf("游戏规则：");
	SetPos(15, 7);
	printf("1.使用WASD控制方向");
	SetPos(15, 8);
	printf("2.吃@得分，加速升级");
	SetPos(15, 9);
	printf("3.碰撞墙壁或自身失败");
	SetPos(15, 10);
	printf("4.按空格暂停/继续");
	SetPos(15, 11);
	printf("5.F1加速，F2减速");
	SetPos(15, 13);
	system("pause");
}

int main() {
	// 获取控制台句柄
	hOut = GetStdHandle(STD_OUTPUT_HANDLE);
	// 隐藏光标
	GetConsoleCursorInfo(hOut, &cci);
	cci.bVisible = false;
	SetConsoleCursorInfo(hOut, &cci);
	
	// 设置窗口大小
	system("mode con cols=100 lines=30");
	
	Welcome();
	
	while (1) {
		KeyboardControl();
		if (status == RUNNING) {
			MoveSnake();
			Sleep(sleeptime);
		}
		else if (status == FAIL) {
			GameOver();
		}
		else if (status == QUIT) {
			break;
		}
		else if (status == PAUSE) {
			Sleep(100);
		}
	}
	
	free(snake.nodes);
	return 0;
}
